package com.authine.cloudpivot.ext.controller.export;

import com.alibaba.fastjson.JSONObject;
import com.authine.cloudpivot.engine.api.model.application.AppPackageModel;
import com.authine.cloudpivot.engine.api.model.organization.UserModel;
import com.authine.cloudpivot.engine.api.model.permission.AppPackagePermissionModel;
import com.authine.cloudpivot.engine.api.model.permission.AppPackageScopeModel;
import com.authine.cloudpivot.engine.api.model.permission.DepartmentScopeModel;
import com.authine.cloudpivot.engine.api.model.permission.PermissionGroupModel;
import com.authine.cloudpivot.engine.api.model.runtime.WorkItemModel;
import com.authine.cloudpivot.engine.api.model.runtime.WorkflowInstanceModel;
import com.authine.cloudpivot.engine.api.model.workflow.WorkflowTemplateHeaderModel;
import com.authine.cloudpivot.engine.enums.ErrCode;
import com.authine.cloudpivot.engine.enums.status.WorkItemApprovalStatus;
import com.authine.cloudpivot.engine.enums.status.WorkflowInstanceStatus;
import com.authine.cloudpivot.engine.enums.type.VisibleType;
import com.authine.cloudpivot.web.api.controller.runtime.WorkflowInstanceController;
import com.authine.cloudpivot.web.api.controller.system.SystemAdminController;
import com.authine.cloudpivot.web.api.view.PageVO;
import com.authine.cloudpivot.web.api.view.ResponseResult;
import com.authine.cloudpivot.web.api.view.runtime.*;
import com.authine.cloudpivot.web.api.view.system.AdminVO;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/export")
@Slf4j
public class ExportInfoController extends WorkflowInstanceController {
    @Value("${export.exportSearchWorkitems}")
    private String exportSearchWorkitems;
    @Value("${export.exportFinishedWorkitems}")
    private String exportFinishedWorkitems;
    @Value("${export.exportMyInstances}")
    private String exportMyInstances;
    @Value("${export.exportMyInstances1}")
    private String exportMyInstances1;


    @SneakyThrows
    @PostMapping("/exportSearchWorkitems")
    @ResponseBody
    public ResponseResult<String> exportSearchWorkitems(@ModelAttribute WorkItemSearchVO workItemSearchVO,HttpServletResponse response) {
        workItemSearchVO.setUserId(this.getUserId());
        workItemSearchVO.setPage(0);
        workItemSearchVO.setSize(99999);
        ResponseResult<PageVO<WorkItemVO>> pageVOResponseResult = this.handleSearchWorkItems(workItemSearchVO);
        List<WorkItemVO> content = pageVOResponseResult.getData().getContent();
        for (WorkItemVO workItemVO : content) {
            String activityName = workItemVO.getActivityName();
            String instanceName = workItemVO.getInstanceName();
            if (!instanceName.contains(activityName)) {
                instanceName = new StringBuffer(instanceName).append("（").append(workItemVO.getActivityName()).append("）").toString();
                workItemVO.getModel().setInstanceName(instanceName);
            }
        }
        if (0L ==pageVOResponseResult.getErrcode()) {
            List<WorkItemVO> content1 = pageVOResponseResult.getData().getContent();
            File f = new File(System.getProperty("user.dir")+exportSearchWorkitems);
            POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(f));
            HSSFWorkbook wb = new HSSFWorkbook(fs);
            HSSFSheet sheet = wb.getSheet("Sheet1");
            if (CollectionUtils.isNotEmpty(content1)){
                int rowIndex = 2;
                for (int i = 0; i < content1.size(); i++) {
                    sheet.createRow(rowIndex);
                    int cellnum = 0;
                    //流程实例名称
                    setCellStrValue(sheet,rowIndex,cellnum++,content1.get(i).getInstanceName());
                    //单据号
                    setCellStrValue(sheet,rowIndex,cellnum++,content1.get(i).getSequenceNo());
                    //发起人
                    setCellStrValue(sheet,rowIndex,cellnum++,content1.get(i).getOriginatorName());
                    //停留时间
//                    Date startTime = content1.get(i).getStartTime();
//                    //获取时间戳
//                    long time = startTime.getTime();
                    Long time = content1.get(i).getStayTime();
                    long l = time / 1000 / 3600 / 24;
                    long l1 = time / 1000 / 3600 % 24;
                    long l2 = time / 1000 / 60 % 60;
                    String timeStr = l+"天"+l1+"小时"+l2+"分钟";
                    setCellStrValue(sheet,rowIndex,cellnum++,timeStr);
                    //当前节点名称
                    setCellStrValue(sheet,rowIndex,cellnum++,content1.get(i).getActivityName());
                    //流程模板名称
                    setCellStrValue(sheet,rowIndex,cellnum++,content1.get(i).getWorkflowName());
                    rowIndex++;
                }

            }
            //输出Excel文件
            OutputStream output= response.getOutputStream();
            response.reset();
            //中文名称要进行编码处理
            response.setHeader("Content-disposition", "attachment; filename=" + new String("我的待办导出表".getBytes("GB2312"),"ISO8859-1")+".xls");
            response.setContentType("application/msexcel");
            wb.write(output);
            output.close();
            return null;
        }
        return null;
    }
    @SneakyThrows
    @PostMapping("/exportFinishedWorkitems")
    @ResponseBody
    public ResponseResult<String> exportFinishedWorkitems(@ModelAttribute WorkItemSearchVO workItemSearchVO,HttpServletResponse response) {
        workItemSearchVO.setUserId(this.getUserId());
        if (StringUtils.isNotEmpty(workItemSearchVO.getWorkflowName())||StringUtils.isNotEmpty(workItemSearchVO.getWorkflowCode())||
                StringUtils.isNotEmpty(workItemSearchVO.getOriginator())||ObjectUtils.isNotEmpty(workItemSearchVO.getUnitType())||
                ObjectUtils.isNotEmpty(workItemSearchVO.getInstanceState())||StringUtils.isNotEmpty(workItemSearchVO.getStartTime())||
                StringUtils.isNotEmpty(workItemSearchVO.getEndTime())){
            workItemSearchVO.setPage(0);
            workItemSearchVO.setSize(99999);
        }else {
            workItemSearchVO.setPage(0);
            workItemSearchVO.setSize(500);
        }
        ResponseResult<PageVO<WorkItemVO>> pageVOResponseResult = this.handlerListFinishedWorkItems(workItemSearchVO);

        if (0L ==pageVOResponseResult.getErrcode()) {
            List<WorkItemVO> content1 = pageVOResponseResult.getData().getContent();
            File f = new File(System.getProperty("user.dir")+exportFinishedWorkitems);
            POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(f));
            HSSFWorkbook wb = new HSSFWorkbook(fs);
            HSSFSheet sheet = wb.getSheet("Sheet1");
            if (CollectionUtils.isNotEmpty(content1)){
                int rowIndex = 2;
                for (int i = 0; i < content1.size(); i++) {
                    sheet.createRow(rowIndex);
                    int cellnum = 0;
                    //流程实例名称
                    setCellStrValue(sheet,rowIndex,cellnum++,content1.get(i).getInstanceName());
                    //单据号
                    setCellStrValue(sheet,rowIndex,cellnum++,content1.get(i).getSequenceNo());
                    //发起人
                    setCellStrValue(sheet,rowIndex,cellnum++,content1.get(i).getOriginatorName());
                    //办理节点
                    setCellStrValue(sheet,rowIndex,cellnum++,content1.get(i).getActivityName());
                    //处理结果
                    setCellStrValue(sheet,rowIndex,cellnum++, content1.get(i).getApproval().getName());
                    //流程模板名称
                    setCellStrValue(sheet,rowIndex,cellnum++,content1.get(i).getWorkflowName());
                    rowIndex++;
                }

            }
            //输出Excel文件
            OutputStream output= response.getOutputStream();
            response.reset();
            //中文名称要进行编码处理
            response.setHeader("Content-disposition", "attachment; filename=" + new String("我的已办导出表".getBytes("GB2312"),"ISO8859-1")+".xls");
            response.setContentType("application/msexcel");
            wb.write(output);
            output.close();
            return null;
        }
        return null;
    }


    @SneakyThrows
    @PostMapping("/exportMyInstances")
    @ResponseBody
    public ResponseResult<String> exportMyInstances(@ModelAttribute WorkflowInstanceSearchVO workflowInstanceSearchVO, HttpServletResponse response) {
       // Pageable pageable = PageRequest.of(workflowInstanceSearchVO.getPage(), workflowInstanceSearchVO.getSize());
        List<WorkflowInstanceStatus> instanceStatuses = getInstanceStates(workflowInstanceSearchVO.getInstanceState());
        String userId = getUserId();
        if (instanceStatuses == null) {
            instanceStatuses = Lists.newArrayList();
            instanceStatuses.add(WorkflowInstanceStatus.PROCESSING);
        }
        Pageable pageable;
        workflowInstanceSearchVO.setUserId(userId);
        if (instanceStatuses.contains(WorkflowInstanceStatus.PROCESSING)){
             pageable = PageRequest.of(0, 99999);
        }else {
            if (StringUtils.isNotEmpty(workflowInstanceSearchVO.getWorkflowName())||StringUtils.isNotEmpty(workflowInstanceSearchVO.getWorkflowCode())||
                    StringUtils.isNotEmpty(workflowInstanceSearchVO.getStartTime())||StringUtils.isNotEmpty(workflowInstanceSearchVO.getEndTime())){
                 pageable = PageRequest.of(0, 99999);
            }else {
                 pageable = PageRequest.of(0, 500);
            }
        }


        Page<WorkflowInstanceModel> instancePage = listMyWorkflowInstanceList(workflowInstanceSearchVO, instanceStatuses, pageable);

        if (instancePage == null) {
            return null;
        }

        List<WorkflowInstanceModel> instancePageModels = instancePage.getContent();

        List<WorkflowInstanceVO> instanceVOs = model2voWithWorkflowInstance(instancePageModels);

        for (WorkflowInstanceVO workflowInstanceVO : instanceVOs) {
            if (workflowInstanceVO.getIsTrustStart()) {
                if (userId.equals(workflowInstanceVO.getOriginator())) {
                    //表示这条流程是当前用户委托给别人发起的
                    workflowInstanceVO.setIsTrustor(Boolean.TRUE);
                } else if (userId.equals(workflowInstanceVO.getTrustee())) {
                    //表示这条流程是别人委托给当前用户发起的
                    workflowInstanceVO.setIsTrustor(Boolean.FALSE);
                }
            }
        }

        Page<WorkflowInstanceVO> instanceVOPage = new PageImpl<>(instanceVOs, pageable, instancePage.getTotalElements());


        List<WorkflowInstanceVO> content1 = instanceVOPage.getContent();
        if (instanceStatuses.contains(WorkflowInstanceStatus.PROCESSING)){
            File f = new File(System.getProperty("user.dir")+exportMyInstances);
            POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(f));
            HSSFWorkbook wb = new HSSFWorkbook(fs);
            HSSFSheet sheet = wb.getSheet("Sheet1");
            if (CollectionUtils.isNotEmpty(content1)){
                int rowIndex = 2;
                for (int i = 0; i < content1.size(); i++) {
                    sheet.createRow(rowIndex);
                    int cellnum = 0;
                    //流程实例名称
                    setCellStrValue(sheet,rowIndex,cellnum++,content1.get(i).getInstanceName());
                    //单据号
                    setCellStrValue(sheet,rowIndex,cellnum++,content1.get(i).getSequenceNo());
                    //已用时
                    Long time = content1.get(i).getStayTime();
                    //获取时间戳
                    //long time = startTime.getTime();
                    long l = time / 1000 / 3600 / 24;
                    long l1 = time / 1000 / 3600 % 24;
                    long l2 = time / 1000 / 60 % 60;
                    String timeStr = l+"天"+l1+"小时"+l2+"分钟";
                    setCellStrValue(sheet,rowIndex,cellnum++,timeStr);
                    //当前处理人
                    setCellStrValue(sheet,rowIndex,cellnum++,MapUtils.getString(content1.get(i).getParticipants(),"name"));
                    //流程模板名称
                    setCellStrValue(sheet,rowIndex,cellnum++,content1.get(i).getWorkflowName());
                    rowIndex++;
                }

            }
            //输出Excel文件
            OutputStream output= response.getOutputStream();
            response.reset();
            //中文名称要进行编码处理
            response.setHeader("Content-disposition", "attachment; filename=" + new String("我的流程导出表".getBytes("GB2312"),"ISO8859-1")+".xls");
            response.setContentType("application/msexcel");
            wb.write(output);
            output.close();
            return null;
        }else {
            File f = new File(System.getProperty("user.dir")+exportMyInstances1);
            POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(f));
            HSSFWorkbook wb = new HSSFWorkbook(fs);
            HSSFSheet sheet = wb.getSheet("Sheet1");
            if (instanceStatuses.contains(WorkflowInstanceStatus.CANCELED)){
                setCellStrValues(sheet,1,3,"作废时间");
            }
            if (CollectionUtils.isNotEmpty(content1)){
                int rowIndex = 2;
                for (int i = 0; i < content1.size(); i++) {
                    sheet.createRow(rowIndex);
                    int cellnum = 0;
                    //流程实例名称
                    setCellStrValue(sheet,rowIndex,cellnum++,content1.get(i).getInstanceName());
                    //单据号
                    setCellStrValue(sheet,rowIndex,cellnum++,content1.get(i).getSequenceNo());
                    //发起时间
                    Date startTime = content1.get(i).getModel().getStartTime();
                    String format = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(startTime);
                    setCellStrValue(sheet,rowIndex,cellnum++,format);
                    //完成时间
                    Date finishTime = content1.get(i).getModel().getFinishTime();
                    String format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(finishTime);
                    setCellStrValue(sheet,rowIndex,cellnum++,format1);
                    //流程模板名称
                    setCellStrValue(sheet,rowIndex,cellnum++,content1.get(i).getWorkflowName());
                    rowIndex++;
                }

            }
            //输出Excel文件
            OutputStream output= response.getOutputStream();
            response.reset();
            //中文名称要进行编码处理
            response.setHeader("Content-disposition", "attachment; filename=" + new String("我的流程导出表".getBytes("GB2312"),"ISO8859-1")+".xls");
            response.setContentType("application/msexcel");
            wb.write(output);
            output.close();
            return null;
        }

    }


    private void setCellStrValue(HSSFSheet sheet, int rowIndex, int cellnum, String value) {
        if(value != null) {
            HSSFCell cell = sheet.getRow(rowIndex).createCell(cellnum);
            cell.setCellValue(value);
        }

    }

    private void setCellStrValues(HSSFSheet sheet, int rowIndex, int cellnum, String value) {
        if(value != null) {
            HSSFCell cell = sheet.getRow(rowIndex).getCell(cellnum);
            cell.setCellValue(value);
        }

    }

    /**
     * 根据字符串获取流程状态
     * @param instanceStateStr 流程实例状态字符串（以逗号拼接）
     * @return List<WorkflowInstanceStatus>
     */
    private List<WorkflowInstanceStatus> getInstanceStates(String instanceStateStr) {
        List<WorkflowInstanceStatus> statuses = null;
        if (StringUtils.isBlank(instanceStateStr)) {
            return statuses;
        }
        if (instanceStateStr.contains(",")) {
            statuses = Lists.newArrayList();
            String[] instances = instanceStateStr.split(",");
            for (String instance : instances) {
                WorkflowInstanceStatus status = null;
                try {
                    status = WorkflowInstanceStatus.valueOf(instance);
                } catch (IllegalArgumentException e) {

                }
                if (status != null) {
                    statuses.add(status);
                }
            }
            return statuses;
        } else {
            WorkflowInstanceStatus status = null;
            try {
                status = WorkflowInstanceStatus.valueOf(instanceStateStr);
            } catch (IllegalArgumentException e) {

            }
            if (status != null) {
                statuses = Lists.newArrayList();
                statuses.add(status);
            }
            return statuses;
        }
    }

    private List<WorkflowInstanceVO> model2voWithWorkflowInstance(List<WorkflowInstanceModel> instancePageModels) {
        if (CollectionUtils.isEmpty(instancePageModels)) {
            return new ArrayList<>();
        }
        Set<String> userIds = new HashSet<>();
        instancePageModels.forEach(workflowInstanceModel -> {
            if (StringUtils.isNotBlank(workflowInstanceModel.getOriginator())) {
                userIds.add(workflowInstanceModel.getOriginator());
            }
            if (StringUtils.isNotBlank(workflowInstanceModel.getParticipant())) {
                userIds.add(workflowInstanceModel.getParticipant());
            }
        });
        Map<String, UserModel> userModelMap = getOrganizationFacade().getUsers(new ArrayList<>(userIds));
        Map<String, WorkflowTemplateHeaderModel> workflowTemplateHeaderModelMap = Maps.newHashMap();
        Map<String, String> containerNameMap = Maps.newHashMapWithExpectedSize(instancePageModels.size());

        List<WorkflowInstanceVO> instanceVOs = instancePageModels.stream().filter(Objects::nonNull).map(instanceModel -> {
            WorkflowInstanceVO instanceVO = new WorkflowInstanceVO(instanceModel);
            WorkflowTemplateHeaderModel header = getAndCacheWorkflowTemplateHeaderModel(workflowTemplateHeaderModelMap, instanceModel.getWorkflowCode());
            instanceVO.setName_i18n(header == null ? null : header.getName_i18n());
            instanceVO.setWorkflowName(header == null ? null : header.getWorkflowName());
            instanceVO.setSequenceNo(instanceModel.getSequenceNo());
            instanceVO.setImgUrl(getUserImg(userModelMap, instanceModel.getOriginator()));
            instanceVO.setParticipantImgUrl(getUserImg(userModelMap, instanceModel.getParticipant()));
            //找子流程
            setChildWorkflowParticipant(instanceVO, instanceModel);
            instanceVO.setActivityCode(instanceModel.getActivityCode());
            instanceVO.setActivityName(instanceModel.getActivityName());
            if (StringUtils.isNotBlank(instanceModel.getAppCode())) {
                AppPackageModel appPackageModel = getAppManagementFacade().getAppPackageByCode(instanceModel.getAppCode());
                if (appPackageModel != null) {
                    instanceVO.setAppName(appPackageModel.getName());
                }
            }
            if (StringUtils.isNotBlank(instanceModel.getSource())) {
                instanceVO.setWorkflowName(instanceModel.getWorkflowName());
                instanceVO.setContainerCode(instanceModel.getSource());
                instanceVO.setContainerName(getContainerName(instanceModel, containerNameMap));
            }
            return instanceVO;
        }).collect(Collectors.toList());
        workflowTemplateHeaderModelMap.clear();
        if (userModelMap != null) {
            userModelMap.clear();
        }
        return instanceVOs;
    }

    private void setChildWorkflowParticipant(WorkflowInstanceVO instanceVO, WorkflowInstanceModel workflowInstanceModel) {
        if (StringUtils.isNotBlank(workflowInstanceModel.getParticipant())) {
            return;
        }
        if (WorkflowInstanceStatus.PROCESSING != workflowInstanceModel.getState()) {
            return;
        }
        List<WorkflowInstanceModel> childInstanceModels = getWorkflowInstanceFacade().getWorkflowInstanceByParentId(workflowInstanceModel.getId());
        if (CollectionUtils.isEmpty(childInstanceModels)) {
            return;
        }
        WorkflowInstanceModel childInstanceModel = childInstanceModels.stream().filter(child -> WorkflowInstanceStatus.PROCESSING == child.getState()).findAny().orElse(null);
        if (childInstanceModel == null) {
            return;
        }
        List<WorkItemModel> workItemModels = getWorkflowInstanceFacade().getWorkItems(childInstanceModel.getId(), Boolean.FALSE);
        if (CollectionUtils.isEmpty(workItemModels)) {
            return;
        }
        workflowInstanceModel.setParticipant(workItemModels.get(0).getParticipant());
        workflowInstanceModel.setParticipantName(workItemModels.get(0).getParticipantName());
        instanceVO.setParticipantImgUrl(getUserImg(workItemModels.get(0).getParticipant()));
    }


}
